/*
* Copyright (C) 2020 ~ 2024 chaigec All Rights Reserved.
*
* Author:     chaigec <chaigec@163.com>
* Maintainer: chaigec <chaigec@163.com>

 * Use of this source code is governed by MIT license that can be found in the
 * LICENSE file in the root of the source tree. All contributing project authors
 * may be found in the AUTHORS file in the root of the source tree.
*/

#include "MkRtmpPublisher.h"
#include "MkFlv/MkFlvMuxer.h"
#include "MkRtmpMuxer.h"
#include "MkUtil/MkLog.h"

#define PusherOutChunkSize 60000
CMkRtmpPublisher::CMkRtmpPublisher(CMkEvent* pEvent, CMkTimer* pTimer, const MkEventRemovedCallback& RemoveCb)
    : CMkRtmpClient(pEvent, pTimer, RemoveCb)
    , m_ReadyCb(nullptr)
    , m_bSendMetaData(FALSE)
    , m_nMaxLen(Len2K)
    , m_nOffset(0)
    , m_pBuffer(nullptr)
{
    m_pBuffer = (Uint8*)malloc(m_nMaxLen);
}

Uint32 CMkRtmpPublisher::Start(const MkString& RtmpUrl, const CMkVideoParam& VideoParam, const CMkAudioParam& AudioParam, const Uint32& FileSize, const Uint32& Duration, const MkRtmpPusherReadyCallback& ReadyCb)
{
    m_VideoParam = VideoParam;
    m_AudioParam = AudioParam;
    m_ReadyCb = ReadyCb;
    return ConnectUrl(RtmpUrl);
}

Uint32 CMkRtmpPublisher::Stop()
{
    return Close();
}

Uint32 CMkRtmpPublisher::SendEsPacket(const MkEsPacket& EsPacket)
{
    CMkBufferList FlvList;
    CMkBufferList SendList;
    m_nOffset = 0;
    Uint32 ErrorCode = NoneError;
    if (!m_bSendMetaData) {
        CMkFlvMuxer::PacketScriptTag(m_VideoParam, m_AudioParam, m_FileSize, m_Duration, m_pBuffer, m_nMaxLen, m_nOffset, FlvList, TRUE);
        CMkRtmpMuxer::PacketRtmpPacket(m_OutChunkSize, MkRtmpHeaderFmt0, RtmpMsgAmf0, ChunkSystem, 0, m_pBuffer, m_nMaxLen, m_nOffset, FlvList, SendList);
        ErrorCode = Send(SendList);
        MkCheckErrorLog(ErrorCode, "send failed\n");
        FlvList.Clear();
        SendList.Clear();
        m_nOffset = 0;

        if (MkCodecUnknown != m_VideoParam.GetCodec()) {
            CMkFlvMuxer::PacketVideoTagPreparation(m_VideoParam, m_pBuffer, m_nMaxLen, m_nOffset, FlvList, TRUE);
            CMkRtmpMuxer::PacketRtmpPacket(m_OutChunkSize, MkRtmpHeaderFmt0, RtmpMsgVideo, ChunkSystem, 0, m_pBuffer, m_nMaxLen, m_nOffset, FlvList, SendList);
            ErrorCode = Send(SendList);
            MkCheckErrorLog(ErrorCode, "send failed\n");
            FlvList.Clear();
            SendList.Clear();
            m_nOffset = 0;
        }

        if (MkCodecUnknown != m_AudioParam.GetCodec()) {
            CMkFlvMuxer::PacketAudioTagPreparation(m_AudioParam, m_pBuffer, m_nMaxLen, m_nOffset, FlvList, TRUE);
            CMkRtmpMuxer::PacketRtmpPacket(m_OutChunkSize, MkRtmpHeaderFmt0, RtmpMsgVideo, ChunkSystem, 0, m_pBuffer, m_nMaxLen, m_nOffset, FlvList, SendList);
            ErrorCode = Send(SendList);
            MkCheckErrorLog(ErrorCode, "send failed\n");
            FlvList.Clear();
            SendList.Clear();
            m_nOffset = 0;
        }

        m_bSendMetaData = TRUE;
    }

    CMkFlvMuxer::PacketEsPacket(m_VideoParam, m_AudioParam, EsPacket, m_pBuffer, m_nMaxLen, m_nOffset, FlvList, TRUE);
    CMkRtmpMuxer::PacketRtmpPacket(m_OutChunkSize, MkRtmpHeaderFmt0, MkCodecCavs < EsPacket.CodecType ? RtmpMsgAudio : RtmpMsgVideo, ChunkSystem, 0, m_pBuffer, m_nMaxLen, m_nOffset, FlvList, SendList);
    m_nOffset = 0;
    return Send(SendList);
}

Uint32 CMkRtmpPublisher::OnHandSharked()
{
    SendChunkSize(PusherOutChunkSize);
    return SendConnect(TRUE);
}

Uint32 CMkRtmpPublisher::OnConnectResult(BOOL bSuccess)
{
    if (bSuccess) {
        SendReleaseStream();
        SendFcPublish();
        SendCreateStream();
    } else {
        Close();
        return SocketClosed;
    }
    return NoneError;
}

Uint32 CMkRtmpPublisher::OnCreateStreamResult(BOOL bSuccess)
{
    if (bSuccess) {
        SendPublish();
    } else {
        Close();
        return SocketClosed;
    }
    return NoneError;
}

Uint32 CMkRtmpPublisher::OnPublishResult(const MkString Level, const MkString& Description, const MkString& Code)
{
    if ("status" == Level) {
        if (m_ReadyCb) {
            m_ReadyCb();
        }
    } else if ("error" == Level) {
        MkErrorLog("publish failed desc:%s\n", Description.c_str());
        Close();
        return SocketClosed;
    }
    return NoneError;
}

CMkRtmpPublisher::~CMkRtmpPublisher()
{
    MkFree(m_pBuffer);
}

